Let’s import at all of the data that Simon and Matt pulled:

library(tidyverse)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
── Attaching packages ─────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.2.1     ✔ purrr   0.3.2
✔ tibble  2.1.3     ✔ dplyr   0.8.3
✔ tidyr   1.0.0     ✔ stringr 1.4.0
✔ readr   1.3.1     ✔ forcats 0.4.0
── Conflicts ────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(gridExtra)

Attaching package: ‘gridExtra’

The following object is masked from ‘package:dplyr’:

    combine
library(maps)

Attaching package: ‘maps’

The following object is masked from ‘package:purrr’:

    map
library(ggthemes)

DeltasClean <- read_csv("../data/out/deltas_clean.csv")
Parsed with column specification:
cols(
  Delta = col_character(),
  location = col_character(),
  surface = col_character(),
  year = col_double(),
  month = col_double(),
  ndvi = col_double(),
  red = col_double(),
  evi = col_double(),
  savi = col_double(),
  gr = col_double(),
  ndssi = col_double()
)
DeltaLocations <- read_csv("../data/DeltaLocations.csv")
Parsed with column specification:
cols(
  Deltas = col_character(),
  Lat = col_double(),
  Lon = col_double()
)

As a reminder, for each of the 47 deltas there are measurements of Land & Water areas at Upstream, Downstream and ‘Middle’ locations on the delta. We first lump all the observations together, and look to see which Deltas have many observations:

#counts per delta
DeltaCounts <- count(DeltasClean, Delta)
DeltaCounts

Now, by each month.. where the colorbar represents the number of observations (n) for each month for a given delta:

DeltaObsPerMonth <- count(DeltasClean, Delta, month)

ggplot(DeltaObsPerMonth, aes(y = Delta, x = month, fill=n)) + geom_tile() + 
  scale_x_discrete(limits = c(1:12), breaks = c(1:12)) +
  expand_limits(x = c(1,12)) + 
  scale_fill_gradient( trans = 'log' )

In the above heat map, dark colors (and no color) represent data paucity (and data gaps). Deltas with light colors (e.g., the Parana, Nile, Ebro, Colorado, Brahmani) have lots of data, spread out through the months of the year.

I’ll remove/subset the deltas with sparse coverage (specifically, months with no coverage)….


# need 10 data points per month for NDSSI and NDVI
EnoughObsPerMonth <- DeltasClean %>%
  count(Delta, month, surface) %>% 
  group_by(surface) %>%
  filter( n >= 5)

#find deltas missing a given month of observations
DeltaMonthCounts <- EnoughObsPerMonth %>%
  ungroup() %>%
  count(Delta)

# need 12 months of water and land obs, so 24 mo total
EnoughMonths <- DeltaMonthCounts %>%
 filter( n == 24)

CompleteObsDeltas <- pull(EnoughMonths, Delta)

#remove them
DeltasCleaner <- DeltasClean %>%
  filter(Delta %in% CompleteObsDeltas)

#add the real dates in month date format
DeltasCleaner$date <- as.Date(paste(DeltasCleaner$year, DeltasCleaner$month, "01", sep="-"), "%Y-%m-%d")

#remove intermediate data
rm(CompleteObsDeltas, EnoughMonths, DeltaMonthCounts)

#EnoughMonths

and extract some metrics; specifically I will make a timeseries of NDVI and NDSSI for each delta using the mean value for each month.

From a quick look at the dat (not shown until much later in the doc):

#take the mean NDVI and NDSSI for each month, for each delta
DeltaMeans <- DeltasCleaner %>%
  group_by(Delta, month, surface) %>%
  summarize(MeanNDVI = mean(ndvi, na.rm = TRUE), MeanNDSSI = mean(ndssi, na.rm = TRUE))

#make a 9 column data frame with:
#delta, 
#max and min NDVI month, 
#NDSSI max and min month, 
#max and min values for both NDVI and NDSSI

#####

DeltaMaxNDVI <- 
  DeltaMeans %>% 
  filter(surface == 'Land')  %>% 
  select (-c(MeanNDSSI)) %>% 
  group_by(Delta) %>% 
  slice(which.max(MeanNDVI)) %>% 
  rename(MaxMeanNDVImonth = month, MaxMeanNDVI = MeanNDVI)

DeltaMaxNDSSI <- 
  DeltaMeans %>% 
  filter(surface == 'Water')  %>% 
  select (-c(MeanNDVI)) %>% 
  group_by(Delta) %>% 
  slice(which.max(MeanNDSSI)) %>% 
  rename(MaxMeanNDSSImonth = month, MaxMeanNDSSI = MeanNDSSI)


DeltaMinNDVI <- 
  DeltaMeans %>% 
  filter(surface == 'Land')  %>% 
  select (-c(MeanNDSSI)) %>% 
  group_by(Delta) %>% 
  slice(which.min(MeanNDVI)) %>% 
  rename(MinMeanNDVImonth = month, MinMeanNDVI = MeanNDVI)

DeltaMinNDSSI <- 
  DeltaMeans %>% 
  filter(surface == 'Water')  %>% 
  select (-c(MeanNDVI)) %>% 
  group_by(Delta) %>% 
  slice(which.min(MeanNDSSI)) %>% 
  rename(MinMeanNDSSImonth = month, MinMeanNDSSI = MeanNDSSI)


#join into 1 dataframe
DeltaMaxMin <- left_join(DeltaMaxNDVI, DeltaMaxNDSSI, by = 'Delta') %>% 
  left_join(.,DeltaMinNDVI, by = 'Delta') %>% 
  left_join(.,DeltaMinNDSSI, by = 'Delta')

#remove intermediate data
rm(DeltaMaxNDVI, DeltaMaxNDSSI, DeltaMinNDSSI,DeltaMinNDVI)

And now we can look at the phase shifts between these two time series (the timeseries of mean NDVI and mean NDSSI). Here are the phase shifts (in month) for each delta:

#compare offset
DeltaMaxMin <- mutate(DeltaMaxMin, 
                      MinOffset = if_else(abs(MinMeanNDVImonth - MinMeanNDSSImonth) > 6, 
                                          12 - abs(MinMeanNDVImonth - MinMeanNDSSImonth),
                                          abs(MinMeanNDVImonth - MinMeanNDSSImonth)),
                      MaxOffset = if_else(abs(MaxMeanNDVImonth - MaxMeanNDSSImonth) > 6, 
                                         12 - abs(MaxMeanNDVImonth - MaxMeanNDSSImonth),
                                          abs(MaxMeanNDVImonth - MaxMeanNDSSImonth)),
                      OffsetDiff = abs(MaxOffset - MinOffset),
                      rangeNDVI = (MaxMeanNDVI - MinMeanNDVI), 
                      rangeNDSSI = (MaxMeanNDSSI - MinMeanNDSSI))

# DeltaMaxMin <- 
#   DeltaMaxMin   %>%
#   select (c(Delta, MinOffset, MaxOffset, OffsetDiff, rangeNDVI, rangeNDSSI,MaxMeanNDSSI,MinMeanNDSSI,MaxMeanNDVI,MinMeanNDVI)) 

DeltaMaxMin

ggplot(DeltaMaxMin, aes(y = Delta, x = MaxOffset)) + geom_point() + 
  scale_x_discrete(limits = c(1:6), breaks = c(1:6)) +
  expand_limits(x = c(0,6))  + 
  ggtitle("MaxOffset")


ggplot(DeltaMaxMin, aes(y = Delta, x = MinOffset)) + geom_point() + 
  scale_x_discrete(limits = c(1:6), breaks = c(1:6)) +
  expand_limits(x = c(0,6))  + 
  ggtitle("MinOffset")


ggplot(DeltaMaxMin, aes(y = Delta, x = OffsetDiff)) + geom_point() + 
  scale_x_discrete(limits = c(1:6), breaks = c(1:6)) +
  expand_limits(x = c(0,6))  + 
  ggtitle("Offset Difference")

And here are the phase shifts/offsets against other measured parameters for each delta. The range, max and mean of NDVI and NDSSI is calculated from the timeseries, so it is really the max, min, and range of the monthly means (i.e., the maximum of the means, the minimum of the means, and the range of the mean). Offset is measured in months.

slice1 <- ggplot(DeltaMaxMin, aes(y = rangeNDVI, x = MaxOffset)) + geom_point() 
# + scale_x_discrete(limits = c(1:6), breaks = c(1:6)) + expand_limits(x = c(1,6)) 

slice2 <- ggplot(DeltaMaxMin, aes(y = rangeNDVI, x = rangeNDSSI)) + geom_point() 
slice3 <- ggplot(DeltaMaxMin, aes(y = rangeNDSSI, x = MaxOffset)) + geom_point() 

slice4 <- ggplot(DeltaMaxMin, aes(y = MaxMeanNDVI, x = rangeNDVI)) + geom_point() 
slice5 <- ggplot(DeltaMaxMin, aes(y = MaxMeanNDVI, x = rangeNDSSI)) + geom_point() 
slice6 <- ggplot(DeltaMaxMin, aes(y = MaxMeanNDVI, x = MaxOffset)) + geom_point() 

slice7 <- ggplot(DeltaMaxMin, aes(y = MaxMeanNDSSI, x = MaxMeanNDVI)) + geom_point() 
slice8 <- ggplot(DeltaMaxMin, aes(y = MaxMeanNDSSI, x = rangeNDSSI)) + geom_point() 
slice9 <- ggplot(DeltaMaxMin, aes(y = MaxMeanNDSSI, x = MaxOffset)) + geom_point() 
slice10 <- ggplot(DeltaMaxMin, aes(y = MaxMeanNDSSI, x = rangeNDVI)) + geom_point() 

grid.arrange(slice1, slice2, slice3, slice4, slice5, slice6, ncol=3)

grid.arrange(slice7, slice8, slice9, slice10, ncol=2)


#remove those panels
rm(slice1, slice2, slice3, slice4, slice5, slice6,slice7, slice8, slice9, slice10)

Join Latitude and longitude data


DeltaDatawLocations <- left_join(DeltaMaxMin, DeltaLocations, by = c("Delta" = "Deltas"))

DeltaDatawLocations <- DeltaDatawLocations %>%
  mutate(Absolute_Latitude= abs(Lat))

plot params vs lat

loc1 <- ggplot(DeltaDatawLocations, aes(y = Absolute_Latitude, x = MaxOffset)) + geom_point() 
loc2 <- ggplot(DeltaDatawLocations, aes(y = Absolute_Latitude, x = rangeNDSSI)) + geom_point() 
loc3 <- ggplot(DeltaDatawLocations, aes(y = Absolute_Latitude, x = rangeNDVI)) + geom_point() 
loc4 <- ggplot(DeltaDatawLocations, aes(y = Absolute_Latitude, x = MaxMeanNDVI)) + geom_point() 
loc5 <- ggplot(DeltaDatawLocations, aes(y = Absolute_Latitude, x = MaxMeanNDSSI)) + geom_point() 

grid.arrange(loc1, loc2, loc3, loc4, loc5, ncol=2)


loc1
ggsave("loc1.pdf", width = 4, height = 4)

loc2
ggsave("loc2.pdf", width = 4, height = 4)

loc3
ggsave("loc3.pdf", width = 4, height = 4)


#remove those panels
rm(loc1, loc2, loc3, loc4, loc5)
#find the linear model 

DeltaOffset_lm <- lm( Absolute_Latitude ~ MaxOffset, data = DeltaDatawLocations) 

summary(DeltaOffset_lm)

Call:
lm(formula = Absolute_Latitude ~ MaxOffset, data = DeltaDatawLocations)

Residuals:
     Min       1Q   Median       3Q      Max 
-28.4079  -5.0293  -0.1842  10.6492  18.1549 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   16.919      3.993   4.237  0.00021 ***
MaxOffset      2.819      1.099   2.564  0.01578 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 11.94 on 29 degrees of freedom
Multiple R-squared:  0.1848,    Adjusted R-squared:  0.1567 
F-statistic: 6.576 on 1 and 29 DF,  p-value: 0.01578
ggplot(DeltaDatawLocations, aes(x = Absolute_Latitude, y = MaxOffset, color = rangeNDSSI)) + geom_point() +
  scale_color_gradient(low = "yellow", high = "red", na.value = NA) + 
  geom_smooth(mapping = aes(x = Absolute_Latitude, y = MaxOffset, ), method=lm ) 

ggsave("NDSSIoffset.pdf", width = 6, height = 4)


ggplot(DeltaDatawLocations, aes(x = Absolute_Latitude, y = MaxOffset, color = rangeNDVI)) + geom_point() +
  scale_color_gradient(low = "yellow", high = "red", na.value = NA) + 
  geom_smooth(mapping = aes(x = Absolute_Latitude, y = MaxOffset, ), method=lm ) 

ggsave("NDVIoffset.pdf", width = 6, height = 4)

Now for the maps:

world <- ggplot() +
  borders("world", colour = "gray85", fill = "gray80") +
  theme_map() 

DeltaOffsetMap <- world +
  geom_point(aes(x = Lon, y = Lat, color = MaxOffset),
             data = DeltaDatawLocations, 
             size = 5) + scale_color_gradient( high = "red", low  = "yellow") +
  ggtitle("Offset Between NDVI peak on Land and NDSSI peak in water")

DeltaOffsetMap
ggsave("DeltaOffsetMap.pdf", width = 6, height = 4)

world <- ggplot() +
  borders("world", colour = "gray85", fill = "gray80") +
  theme_map() 

DeltaNDVIrangeMap <- world +
  geom_point(aes(x = Lon, y = Lat, color = rangeNDVI),
             data = DeltaDatawLocations,
             size = 5) + scale_color_gradient( high = "red", low  = "yellow") + 
  ggtitle("NDVI range")


DeltaNDSSIrangeMap  <- world +
  geom_point(aes(x = Lon, y = Lat, color = rangeNDSSI),
             data = DeltaDatawLocations, 
             size = 5) + scale_color_gradient( high = "red", low = "yellow") + ggtitle("NDSSI range") 

DeltaNDVIrangeMap 
ggsave("DeltaNDVIrangeMap.pdf", width = 6, height = 4)

DeltaNDSSIrangeMap
ggsave("DeltaNDSSIrangeMap.pdf", width = 6, height = 4)

Let’s look at some of the data. To quantify the water, we use NDSSI. to quantify land, we use NDVI.here is the time series for the Parana.

DeltaPlotter <- function(DeltaName) {
  #Counts each month
  numVeg <- DeltasCleaner %>%
    select(Delta, surface, month, ndvi) %>%
    filter(Delta == DeltaName & surface == "Land" & !is.na(ndvi)) %>%
    group_by(month) %>%
    summarize(n = n())
  
  numSed <- DeltasCleaner %>%
    select(Delta, surface, month, ndssi) %>%
    filter(Delta == DeltaName &
             surface == "Water" & !is.na(ndssi)) %>%
    group_by(month) %>%
    summarize(n = n())
  
  #Highlight the Maximum and Minimum Month for each delta, NDVI and NDSSI
  
  #LAND
  Veg <-
    ggplot(data = filter(DeltasCleaner, Delta == DeltaName &
                           surface == "Land")) +
    geom_boxplot(aes(x = month, y = ndvi, group = month)) +
    scale_x_discrete(limits = c(1:12), breaks = c(1:12)) +
    expand_limits(x = c(1, 12), y = c(0, 1)) +
    ggtitle(DeltaName) +
    geom_text(data = numVeg, aes(y = 1.05, x = month, label = n)) +
    geom_boxplot(
      data = filter(
        DeltasCleaner,
        Delta == DeltaName &
          surface == "Land" & month == DeltaMaxMin$MaxMeanNDVImonth[DeltaMaxMin$Delta == DeltaName] 
      ),
      aes(x = month, y = ndvi, group = month),
      fill = "green"
    ) +
    geom_boxplot(
      data = filter(
        DeltasCleaner,
        Delta == DeltaName & 
          surface == "Land" & month == DeltaMaxMin$MinMeanNDVImonth[DeltaMaxMin$Delta ==DeltaName]
      ),
      aes(x = month, y = ndvi, group = month),
      fill = "blue"
    )
  
  
  Sed <-
    ggplot(data = filter(DeltasCleaner, Delta == DeltaName &
                           surface == "Water")) +
    geom_boxplot(aes(x = month, y = ndssi, group = month)) +
    scale_x_discrete(limits = c(1:12), breaks = c(1:12)) +
    expand_limits(x = c(1, 12), y = c(0, 1)) +
    geom_text(data = numSed, aes(y = 1.05, x = month, label = n)) +
    geom_boxplot(
      data = filter(
        DeltasCleaner,
        Delta == DeltaName &
          surface == "Water" & month == DeltaMaxMin$MaxMeanNDSSImonth[DeltaMaxMin$Delta == DeltaName]
      ),
      aes(x = month, y = ndssi, group = month),
      fill = "green"
    ) +
    geom_boxplot(
      data = filter(
        DeltasCleaner,
        Delta == DeltaName &
          surface == "Water" & month == DeltaMaxMin$MinMeanNDSSImonth[DeltaMaxMin$Delta == DeltaName]
      ),
      aes(x = month, y = ndssi, group = month),
      fill = "blue"
    )
  
  return(grid.arrange(Veg, Sed, nrow = 2))
}

Here is an ‘Offset’ example from the Parana:

DeltaPlotter("Parana")

and now an in-phase example from

DeltaPlotter("Magdalena")

and the Ebro:

DeltaPlotter("Krishna")

and the Tana

DeltaPlotter("Tana")

and the Tana

DeltaPlotter("Godavari")

DeltaPlotter("Krishna")

Now for some work with GRDC data:

#import the data (monthly means for 21 stations)
DeltasGRDC  <- read_csv("../data/GRDCstations.csv")
Parsed with column specification:
cols(
  Deltas = col_character(),
  GRDC_Station = col_double(),
  Time_Series_Length = col_character(),
  January = col_double(),
  February = col_double(),
  March = col_double(),
  April = col_double(),
  May = col_double(),
  June = col_double(),
  July = col_double(),
  August = col_double(),
  September = col_double(),
  October = col_double(),
  November = col_double(),
  December = col_double()
)
#calculate the mean of the monthly means
DeltasGRDCwMean <- DeltasGRDC %>% 
    rowwise() %>% 
    mutate(MMD=mean(c(January,February,March,April,
                    May,June,July,August,
                    September,October,November,December)))

DeltasGRDCwMean <- DeltasGRDCwMean %>% 
  rowwise() %>% 
  mutate(Range_Discharge = max(c(January,February,March,April,
              May,June,July,August,
              September,October,November,December)) - 
           min(c(January,February,March,April,
              May,June,July,August,
              September,October,November,December))
           )
        

#join to location data:
DeltawLocGRDC <- left_join(DeltaDatawLocations, DeltasGRDCwMean, by = c("Delta" = "Deltas"))


#plot mean of monthly means against NDSSI
ggplot(DeltawLocGRDC, aes(y = Range_Discharge, x = rangeNDSSI)) + geom_point() + scale_y_continuous(trans='log10')

ggsave("GRDCNDSSI.pdf", width = 6, height = 4)


ggplot(DeltawLocGRDC, aes(y = Range_Discharge, x = MaxMeanNDSSI)) + geom_point() + scale_y_continuous(trans='log10')



#rename the months by numbers and tidy the GRDC data
DeltasDischarge <- DeltasGRDC %>%
  rename(Delta = Deltas,"1" = January, "2"= February, "3"= March, "4"= April,
         "5"=May, "6"=June, "7"=July, "8"= August, "9" = September, "10"=October, 
         "11"=November, "12"=December) %>%
  select(Delta, "1" , "2" , "3", "4","5", "6", "7", "8", "9", "10", "11", "12") %>%
  pivot_longer(-Delta, names_to = "month", values_to = "discharge")

#find max GRDC month for each delta
DeltaMaxDischarge <- 
  DeltasDischarge %>% 
  group_by(Delta) %>% 
  slice(which.max(discharge)) %>% 
  rename(MaxDischargeMonth = month, MaxDischarge = discharge) 


DeltaMaxDischarge$MaxDischargeMonth = as.numeric(DeltaMaxDischarge$MaxDischargeMonth)


#join with other delta data
DeltaMaxMinDischarge <- left_join(DeltaMaxMin, DeltaMaxDischarge, by = 'Delta')

#calculate offset
DeltaMaxMinDischarge <- DeltaMaxMinDischarge %>%
  mutate( DissOff = if_else(abs(MaxDischargeMonth - MaxMeanNDSSImonth) > 6,
                            12 - abs(MaxDischargeMonth - MaxMeanNDSSImonth),
                            abs(MaxDischargeMonth - MaxMeanNDSSImonth))
          )

#Compare offset with NDSSI (deltamaxmin$maxmeanNDSSImonth)
ggplot(DeltaMaxMinDischarge, aes(y = Delta, x = DissOff)) + geom_point() + 
  scale_x_discrete(limits = c(1:6), breaks = c(1:6)) +
  expand_limits(x = c(0,6))  + 
  ggtitle("DisOffset")



#join lat data
DeltaDatawLocations <- left_join(DeltaMaxMinDischarge, DeltaLocations, by = c("Delta" = "Deltas"))

DeltaDatawLocations <- DeltaDatawLocations %>%
  mutate(Absolute_Latitude= abs(Lat))

# plot offset on graph by lat
ggplot(DeltaDatawLocations, aes(x = Absolute_Latitude, y = DissOff)) + geom_point() +
  scale_color_gradient(low = "yellow", high = "red", na.value = NA) 
  #+ geom_smooth(mapping = aes(x = Absolute_Latitude, y = DissOff, ), method=lm ) 

ggsave("DisOffset.pdf", width = 6, height = 4)


#plot offset on map
DeltaDisOffsetMap <- world +
  geom_point(aes(x = Lon, y = Lat, color = DissOff),
             data = DeltaDatawLocations, 
             size = 5) + scale_color_gradient( high = "red", low  = "yellow") +
  ggtitle("Offset Between GRDC discharge peak and NDSSI peak in water")

DeltaDisOffsetMap

#ggsave("DeltaOffsetMap.pdf", width = 6, height = 4)
LS0tCnRpdGxlOiAiRGVsdGFzIE5vdGVib29rIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKTGV0J3MgaW1wb3J0IGF0IGFsbCBvZiB0aGUgZGF0YSB0aGF0IFNpbW9uIGFuZCBNYXR0IHB1bGxlZDoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkobWFwcykKbGlicmFyeShnZ3RoZW1lcykKCkRlbHRhc0NsZWFuIDwtIHJlYWRfY3N2KCIuLi9kYXRhL291dC9kZWx0YXNfY2xlYW4uY3N2IikKRGVsdGFMb2NhdGlvbnMgPC0gcmVhZF9jc3YoIi4uL2RhdGEvRGVsdGFMb2NhdGlvbnMuY3N2IikKYGBgCgpBcyBhIHJlbWluZGVyLCBmb3IgZWFjaCBvZiB0aGUgNDcgZGVsdGFzIHRoZXJlIGFyZSBtZWFzdXJlbWVudHMgb2YgTGFuZCAmIFdhdGVyIGFyZWFzIGF0IFVwc3RyZWFtLCBEb3duc3RyZWFtIGFuZCAnTWlkZGxlJyBsb2NhdGlvbnMgb24gdGhlIGRlbHRhLiBXZSBmaXJzdCBsdW1wIGFsbCB0aGUgb2JzZXJ2YXRpb25zIHRvZ2V0aGVyLCBhbmQgbG9vayB0byBzZWUgd2hpY2ggRGVsdGFzIGhhdmUgbWFueSBvYnNlcnZhdGlvbnM6CgpgYGB7cn0KI2NvdW50cyBwZXIgZGVsdGEKRGVsdGFDb3VudHMgPC0gY291bnQoRGVsdGFzQ2xlYW4sIERlbHRhKQpEZWx0YUNvdW50cwpgYGAKCgpOb3csIGJ5IGVhY2ggbW9udGguLiB3aGVyZSB0aGUgY29sb3JiYXIgcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyAobikgZm9yIGVhY2ggbW9udGggZm9yIGEgZ2l2ZW4gZGVsdGE6CmBgYHtyfQpEZWx0YU9ic1Blck1vbnRoIDwtIGNvdW50KERlbHRhc0NsZWFuLCBEZWx0YSwgbW9udGgpCgpnZ3Bsb3QoRGVsdGFPYnNQZXJNb250aCwgYWVzKHkgPSBEZWx0YSwgeCA9IG1vbnRoLCBmaWxsPW4pKSArIGdlb21fdGlsZSgpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6MTIpLCBicmVha3MgPSBjKDE6MTIpKSArCiAgZXhwYW5kX2xpbWl0cyh4ID0gYygxLDEyKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50KCB0cmFucyA9ICdsb2cnICkKCmBgYAoKCkluIHRoZSBhYm92ZSBoZWF0IG1hcCwgZGFyayBjb2xvcnMgKGFuZCBubyBjb2xvcikgcmVwcmVzZW50IGRhdGEgcGF1Y2l0eSAoYW5kIGRhdGEgZ2FwcykuIERlbHRhcyB3aXRoIGxpZ2h0IGNvbG9ycyAoZS5nLiwgdGhlIFBhcmFuYSwgTmlsZSwgRWJybywgQ29sb3JhZG8sIEJyYWhtYW5pKSBoYXZlIGxvdHMgb2YgZGF0YSwgc3ByZWFkIG91dCB0aHJvdWdoIHRoZSBtb250aHMgb2YgdGhlIHllYXIuCgoKSSdsbCByZW1vdmUvc3Vic2V0IHRoZSBkZWx0YXMgd2l0aCBzcGFyc2UgY292ZXJhZ2UgKHNwZWNpZmljYWxseSwgbW9udGhzIHdpdGggbm8gY292ZXJhZ2UpLi4uLiAKYGBge3J9CgojIG5lZWQgMTAgZGF0YSBwb2ludHMgcGVyIG1vbnRoIGZvciBORFNTSSBhbmQgTkRWSQpFbm91Z2hPYnNQZXJNb250aCA8LSBEZWx0YXNDbGVhbiAlPiUKICBjb3VudChEZWx0YSwgbW9udGgsIHN1cmZhY2UpICU+JSAKICBncm91cF9ieShzdXJmYWNlKSAlPiUKICBmaWx0ZXIoIG4gPj0gNSkKCiNmaW5kIGRlbHRhcyBtaXNzaW5nIGEgZ2l2ZW4gbW9udGggb2Ygb2JzZXJ2YXRpb25zCkRlbHRhTW9udGhDb3VudHMgPC0gRW5vdWdoT2JzUGVyTW9udGggJT4lCiAgdW5ncm91cCgpICU+JQogIGNvdW50KERlbHRhKQoKIyBuZWVkIDEyIG1vbnRocyBvZiB3YXRlciBhbmQgbGFuZCBvYnMsIHNvIDI0IG1vIHRvdGFsCkVub3VnaE1vbnRocyA8LSBEZWx0YU1vbnRoQ291bnRzICU+JQogZmlsdGVyKCBuID09IDI0KQoKQ29tcGxldGVPYnNEZWx0YXMgPC0gcHVsbChFbm91Z2hNb250aHMsIERlbHRhKQoKI3JlbW92ZSB0aGVtCkRlbHRhc0NsZWFuZXIgPC0gRGVsdGFzQ2xlYW4gJT4lCiAgZmlsdGVyKERlbHRhICVpbiUgQ29tcGxldGVPYnNEZWx0YXMpCgojYWRkIHRoZSByZWFsIGRhdGVzIGluIG1vbnRoIGRhdGUgZm9ybWF0CkRlbHRhc0NsZWFuZXIkZGF0ZSA8LSBhcy5EYXRlKHBhc3RlKERlbHRhc0NsZWFuZXIkeWVhciwgRGVsdGFzQ2xlYW5lciRtb250aCwgIjAxIiwgc2VwPSItIiksICIlWS0lbS0lZCIpCgojcmVtb3ZlIGludGVybWVkaWF0ZSBkYXRhCnJtKENvbXBsZXRlT2JzRGVsdGFzLCBFbm91Z2hNb250aHMsIERlbHRhTW9udGhDb3VudHMpCgojRW5vdWdoTW9udGhzCmBgYAoKYW5kIGV4dHJhY3Qgc29tZSBtZXRyaWNzOyBzcGVjaWZpY2FsbHkgSSB3aWxsIG1ha2UgYSB0aW1lc2VyaWVzIG9mIE5EVkkgYW5kIE5EU1NJIGZvciBlYWNoIGRlbHRhIHVzaW5nIHRoZSBtZWFuIHZhbHVlIGZvciBlYWNoIG1vbnRoLgoKRnJvbSBhIHF1aWNrIGxvb2sgYXQgdGhlIGRhdCAobm90IHNob3duIHVudGlsIG11Y2ggbGF0ZXIgaW4gdGhlIGRvYyk6CgoqIFBlYWtzIGluIE5EVkkgYXJlIG5vdCBhbHdheXMgY29ycmVsYXRlZCB3aXRoIHBlYWtzIGluIE5EU1NJLiBpbiBvdGhlciB3b3JkcywgbWF4aW11bXMgaW4gc2VkIGNvbmNlbnRyYXRpb24gYXJlIG5vdCBkdXJpbmcgbWF4aW11bXMgaW4gc3RhbmRpbmcgYmlvbWFzcy4KKiBUaGUgcGVha3MgaW4gYm90aCB0aW1lc2VyaWVzIHNoaWZ0IGFyb3VuZCBkZXBlbmRpbmcgb24gdGhlIGRlbHRhOgogICArIGxvb2sgYXQgdGhlIGNvcnJlbGF0aW9uIGluIHRoZSBOaWxlLgogICArIFRoZSBhbnRpY29ycmVsYXRpb24gaW4gdGhlIEVicm8sCiAgICsgVGhlIHNsaWdodCBwaGFzZSBzaGlmdCBpbiB0aGUgUGFyYW5hLgoKCmBgYHtyICBpbmNsdWRlID0gVFJVRX0KI3Rha2UgdGhlIG1lYW4gTkRWSSBhbmQgTkRTU0kgZm9yIGVhY2ggbW9udGgsIGZvciBlYWNoIGRlbHRhCkRlbHRhTWVhbnMgPC0gRGVsdGFzQ2xlYW5lciAlPiUKICBncm91cF9ieShEZWx0YSwgbW9udGgsIHN1cmZhY2UpICU+JQogIHN1bW1hcml6ZShNZWFuTkRWSSA9IG1lYW4obmR2aSwgbmEucm0gPSBUUlVFKSwgTWVhbk5EU1NJID0gbWVhbihuZHNzaSwgbmEucm0gPSBUUlVFKSkKCiNtYWtlIGEgOSBjb2x1bW4gZGF0YSBmcmFtZSB3aXRoOgojZGVsdGEsIAojbWF4IGFuZCBtaW4gTkRWSSBtb250aCwgCiNORFNTSSBtYXggYW5kIG1pbiBtb250aCwgCiNtYXggYW5kIG1pbiB2YWx1ZXMgZm9yIGJvdGggTkRWSSBhbmQgTkRTU0kKCiMjIyMjCgpEZWx0YU1heE5EVkkgPC0gCiAgRGVsdGFNZWFucyAlPiUgCiAgZmlsdGVyKHN1cmZhY2UgPT0gJ0xhbmQnKSAgJT4lIAogIHNlbGVjdCAoLWMoTWVhbk5EU1NJKSkgJT4lIAogIGdyb3VwX2J5KERlbHRhKSAlPiUgCiAgc2xpY2Uod2hpY2gubWF4KE1lYW5ORFZJKSkgJT4lIAogIHJlbmFtZShNYXhNZWFuTkRWSW1vbnRoID0gbW9udGgsIE1heE1lYW5ORFZJID0gTWVhbk5EVkkpCgpEZWx0YU1heE5EU1NJIDwtIAogIERlbHRhTWVhbnMgJT4lIAogIGZpbHRlcihzdXJmYWNlID09ICdXYXRlcicpICAlPiUgCiAgc2VsZWN0ICgtYyhNZWFuTkRWSSkpICU+JSAKICBncm91cF9ieShEZWx0YSkgJT4lIAogIHNsaWNlKHdoaWNoLm1heChNZWFuTkRTU0kpKSAlPiUgCiAgcmVuYW1lKE1heE1lYW5ORFNTSW1vbnRoID0gbW9udGgsIE1heE1lYW5ORFNTSSA9IE1lYW5ORFNTSSkKCgpEZWx0YU1pbk5EVkkgPC0gCiAgRGVsdGFNZWFucyAlPiUgCiAgZmlsdGVyKHN1cmZhY2UgPT0gJ0xhbmQnKSAgJT4lIAogIHNlbGVjdCAoLWMoTWVhbk5EU1NJKSkgJT4lIAogIGdyb3VwX2J5KERlbHRhKSAlPiUgCiAgc2xpY2Uod2hpY2gubWluKE1lYW5ORFZJKSkgJT4lIAogIHJlbmFtZShNaW5NZWFuTkRWSW1vbnRoID0gbW9udGgsIE1pbk1lYW5ORFZJID0gTWVhbk5EVkkpCgpEZWx0YU1pbk5EU1NJIDwtIAogIERlbHRhTWVhbnMgJT4lIAogIGZpbHRlcihzdXJmYWNlID09ICdXYXRlcicpICAlPiUgCiAgc2VsZWN0ICgtYyhNZWFuTkRWSSkpICU+JSAKICBncm91cF9ieShEZWx0YSkgJT4lIAogIHNsaWNlKHdoaWNoLm1pbihNZWFuTkRTU0kpKSAlPiUgCiAgcmVuYW1lKE1pbk1lYW5ORFNTSW1vbnRoID0gbW9udGgsIE1pbk1lYW5ORFNTSSA9IE1lYW5ORFNTSSkKCgojam9pbiBpbnRvIDEgZGF0YWZyYW1lCkRlbHRhTWF4TWluIDwtIGxlZnRfam9pbihEZWx0YU1heE5EVkksIERlbHRhTWF4TkRTU0ksIGJ5ID0gJ0RlbHRhJykgJT4lIAogIGxlZnRfam9pbiguLERlbHRhTWluTkRWSSwgYnkgPSAnRGVsdGEnKSAlPiUgCiAgbGVmdF9qb2luKC4sRGVsdGFNaW5ORFNTSSwgYnkgPSAnRGVsdGEnKQoKI3JlbW92ZSBpbnRlcm1lZGlhdGUgZGF0YQpybShEZWx0YU1heE5EVkksIERlbHRhTWF4TkRTU0ksIERlbHRhTWluTkRTU0ksRGVsdGFNaW5ORFZJKQoKYGBgCgoKQW5kIG5vdyB3ZSBjYW4gbG9vayBhdCB0aGUgcGhhc2Ugc2hpZnRzIGJldHdlZW4gdGhlc2UgdHdvIHRpbWUgc2VyaWVzICh0aGUgdGltZXNlcmllcyBvZiBtZWFuIE5EVkkgYW5kIG1lYW4gTkRTU0kpLiBIZXJlIGFyZSB0aGUgcGhhc2Ugc2hpZnRzIChpbiBtb250aCkgZm9yIGVhY2ggZGVsdGE6CmBgYHtyIH0KI2NvbXBhcmUgb2Zmc2V0CkRlbHRhTWF4TWluIDwtIG11dGF0ZShEZWx0YU1heE1pbiwgCiAgICAgICAgICAgICAgICAgICAgICBNaW5PZmZzZXQgPSBpZl9lbHNlKGFicyhNaW5NZWFuTkRWSW1vbnRoIC0gTWluTWVhbk5EU1NJbW9udGgpID4gNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEyIC0gYWJzKE1pbk1lYW5ORFZJbW9udGggLSBNaW5NZWFuTkRTU0ltb250aCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFicyhNaW5NZWFuTkRWSW1vbnRoIC0gTWluTWVhbk5EU1NJbW9udGgpKSwKICAgICAgICAgICAgICAgICAgICAgIE1heE9mZnNldCA9IGlmX2Vsc2UoYWJzKE1heE1lYW5ORFZJbW9udGggLSBNYXhNZWFuTkRTU0ltb250aCkgPiA2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMiAtIGFicyhNYXhNZWFuTkRWSW1vbnRoIC0gTWF4TWVhbk5EU1NJbW9udGgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMoTWF4TWVhbk5EVkltb250aCAtIE1heE1lYW5ORFNTSW1vbnRoKSksCiAgICAgICAgICAgICAgICAgICAgICBPZmZzZXREaWZmID0gYWJzKE1heE9mZnNldCAtIE1pbk9mZnNldCksCiAgICAgICAgICAgICAgICAgICAgICByYW5nZU5EVkkgPSAoTWF4TWVhbk5EVkkgLSBNaW5NZWFuTkRWSSksIAogICAgICAgICAgICAgICAgICAgICAgcmFuZ2VORFNTSSA9IChNYXhNZWFuTkRTU0kgLSBNaW5NZWFuTkRTU0kpKQoKIyBEZWx0YU1heE1pbiA8LSAKIyAgIERlbHRhTWF4TWluICAgJT4lCiMgICBzZWxlY3QgKGMoRGVsdGEsIE1pbk9mZnNldCwgTWF4T2Zmc2V0LCBPZmZzZXREaWZmLCByYW5nZU5EVkksIHJhbmdlTkRTU0ksTWF4TWVhbk5EU1NJLE1pbk1lYW5ORFNTSSxNYXhNZWFuTkRWSSxNaW5NZWFuTkRWSSkpIAoKRGVsdGFNYXhNaW4KCmdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSBEZWx0YSwgeCA9IE1heE9mZnNldCkpICsgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6NiksIGJyZWFrcyA9IGMoMTo2KSkgKwogIGV4cGFuZF9saW1pdHMoeCA9IGMoMCw2KSkgICsgCiAgZ2d0aXRsZSgiTWF4T2Zmc2V0IikKCmdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSBEZWx0YSwgeCA9IE1pbk9mZnNldCkpICsgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6NiksIGJyZWFrcyA9IGMoMTo2KSkgKwogIGV4cGFuZF9saW1pdHMoeCA9IGMoMCw2KSkgICsgCiAgZ2d0aXRsZSgiTWluT2Zmc2V0IikKCmdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSBEZWx0YSwgeCA9IE9mZnNldERpZmYpKSArIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygxOjYpLCBicmVha3MgPSBjKDE6NikpICsKICBleHBhbmRfbGltaXRzKHggPSBjKDAsNikpICArIAogIGdndGl0bGUoIk9mZnNldCBEaWZmZXJlbmNlIikKCmBgYAoKICAgQW5kIGhlcmUgYXJlIHRoZSBwaGFzZSBzaGlmdHMvb2Zmc2V0cyBhZ2FpbnN0IG90aGVyIG1lYXN1cmVkIHBhcmFtZXRlcnMgZm9yIGVhY2ggZGVsdGEuIFRoZSByYW5nZSwgbWF4IGFuZCBtZWFuIG9mIE5EVkkgYW5kIE5EU1NJIGlzIGNhbGN1bGF0ZWQgZnJvbSB0aGUgdGltZXNlcmllcywgc28gaXQgaXMgcmVhbGx5IHRoZSBtYXgsIG1pbiwgYW5kIHJhbmdlIG9mIHRoZSBtb250aGx5IG1lYW5zIChpLmUuLCB0aGUgbWF4aW11bSBvZiB0aGUgbWVhbnMsIHRoZSBtaW5pbXVtIG9mIHRoZSBtZWFucywgYW5kIHRoZSByYW5nZSBvZiB0aGUgbWVhbikuIE9mZnNldCBpcyBtZWFzdXJlZCBpbiBtb250aHMuCgpgYGB7cn0Kc2xpY2UxIDwtIGdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSByYW5nZU5EVkksIHggPSBNYXhPZmZzZXQpKSArIGdlb21fcG9pbnQoKSAKIyArIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygxOjYpLCBicmVha3MgPSBjKDE6NikpICsgZXhwYW5kX2xpbWl0cyh4ID0gYygxLDYpKSAKCnNsaWNlMiA8LSBnZ3Bsb3QoRGVsdGFNYXhNaW4sIGFlcyh5ID0gcmFuZ2VORFZJLCB4ID0gcmFuZ2VORFNTSSkpICsgZ2VvbV9wb2ludCgpIApzbGljZTMgPC0gZ2dwbG90KERlbHRhTWF4TWluLCBhZXMoeSA9IHJhbmdlTkRTU0ksIHggPSBNYXhPZmZzZXQpKSArIGdlb21fcG9pbnQoKSAKCnNsaWNlNCA8LSBnZ3Bsb3QoRGVsdGFNYXhNaW4sIGFlcyh5ID0gTWF4TWVhbk5EVkksIHggPSByYW5nZU5EVkkpKSArIGdlb21fcG9pbnQoKSAKc2xpY2U1IDwtIGdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSBNYXhNZWFuTkRWSSwgeCA9IHJhbmdlTkRTU0kpKSArIGdlb21fcG9pbnQoKSAKc2xpY2U2IDwtIGdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSBNYXhNZWFuTkRWSSwgeCA9IE1heE9mZnNldCkpICsgZ2VvbV9wb2ludCgpIAoKc2xpY2U3IDwtIGdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSBNYXhNZWFuTkRTU0ksIHggPSBNYXhNZWFuTkRWSSkpICsgZ2VvbV9wb2ludCgpIApzbGljZTggPC0gZ2dwbG90KERlbHRhTWF4TWluLCBhZXMoeSA9IE1heE1lYW5ORFNTSSwgeCA9IHJhbmdlTkRTU0kpKSArIGdlb21fcG9pbnQoKSAKc2xpY2U5IDwtIGdncGxvdChEZWx0YU1heE1pbiwgYWVzKHkgPSBNYXhNZWFuTkRTU0ksIHggPSBNYXhPZmZzZXQpKSArIGdlb21fcG9pbnQoKSAKc2xpY2UxMCA8LSBnZ3Bsb3QoRGVsdGFNYXhNaW4sIGFlcyh5ID0gTWF4TWVhbk5EU1NJLCB4ID0gcmFuZ2VORFZJKSkgKyBnZW9tX3BvaW50KCkgCgpncmlkLmFycmFuZ2Uoc2xpY2UxLCBzbGljZTIsIHNsaWNlMywgc2xpY2U0LCBzbGljZTUsIHNsaWNlNiwgbmNvbD0zKQpncmlkLmFycmFuZ2Uoc2xpY2U3LCBzbGljZTgsIHNsaWNlOSwgc2xpY2UxMCwgbmNvbD0yKQoKI3JlbW92ZSB0aG9zZSBwYW5lbHMKcm0oc2xpY2UxLCBzbGljZTIsIHNsaWNlMywgc2xpY2U0LCBzbGljZTUsIHNsaWNlNixzbGljZTcsIHNsaWNlOCwgc2xpY2U5LCBzbGljZTEwKQoKYGBgCgoKSm9pbiBMYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGRhdGEKCmBgYHtyfQoKRGVsdGFEYXRhd0xvY2F0aW9ucyA8LSBsZWZ0X2pvaW4oRGVsdGFNYXhNaW4sIERlbHRhTG9jYXRpb25zLCBieSA9IGMoIkRlbHRhIiA9ICJEZWx0YXMiKSkKCkRlbHRhRGF0YXdMb2NhdGlvbnMgPC0gRGVsdGFEYXRhd0xvY2F0aW9ucyAlPiUKICBtdXRhdGUoQWJzb2x1dGVfTGF0aXR1ZGU9IGFicyhMYXQpKQpgYGAKCnBsb3QgcGFyYW1zIHZzIGxhdApgYGB7cn0KbG9jMSA8LSBnZ3Bsb3QoRGVsdGFEYXRhd0xvY2F0aW9ucywgYWVzKHkgPSBBYnNvbHV0ZV9MYXRpdHVkZSwgeCA9IE1heE9mZnNldCkpICsgZ2VvbV9wb2ludCgpIApsb2MyIDwtIGdncGxvdChEZWx0YURhdGF3TG9jYXRpb25zLCBhZXMoeSA9IEFic29sdXRlX0xhdGl0dWRlLCB4ID0gcmFuZ2VORFNTSSkpICsgZ2VvbV9wb2ludCgpIApsb2MzIDwtIGdncGxvdChEZWx0YURhdGF3TG9jYXRpb25zLCBhZXMoeSA9IEFic29sdXRlX0xhdGl0dWRlLCB4ID0gcmFuZ2VORFZJKSkgKyBnZW9tX3BvaW50KCkgCmxvYzQgPC0gZ2dwbG90KERlbHRhRGF0YXdMb2NhdGlvbnMsIGFlcyh5ID0gQWJzb2x1dGVfTGF0aXR1ZGUsIHggPSBNYXhNZWFuTkRWSSkpICsgZ2VvbV9wb2ludCgpIApsb2M1IDwtIGdncGxvdChEZWx0YURhdGF3TG9jYXRpb25zLCBhZXMoeSA9IEFic29sdXRlX0xhdGl0dWRlLCB4ID0gTWF4TWVhbk5EU1NJKSkgKyBnZW9tX3BvaW50KCkgCgpncmlkLmFycmFuZ2UobG9jMSwgbG9jMiwgbG9jMywgbG9jNCwgbG9jNSwgbmNvbD0yKQoKbG9jMQpnZ3NhdmUoImxvYzEucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpsb2MyCmdnc2F2ZSgibG9jMi5wZGYiLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpCmxvYzMKZ2dzYXZlKCJsb2MzLnBkZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNCkKCiNyZW1vdmUgdGhvc2UgcGFuZWxzCnJtKGxvYzEsIGxvYzIsIGxvYzMsIGxvYzQsIGxvYzUpCmBgYAoKYGBge3J9CiNmaW5kIHRoZSBsaW5lYXIgbW9kZWwgCgpEZWx0YU9mZnNldF9sbSA8LSBsbSggQWJzb2x1dGVfTGF0aXR1ZGUgfiBNYXhPZmZzZXQsIGRhdGEgPSBEZWx0YURhdGF3TG9jYXRpb25zKSAKCnN1bW1hcnkoRGVsdGFPZmZzZXRfbG0pCgpnZ3Bsb3QoRGVsdGFEYXRhd0xvY2F0aW9ucywgYWVzKHggPSBBYnNvbHV0ZV9MYXRpdHVkZSwgeSA9IE1heE9mZnNldCwgY29sb3IgPSByYW5nZU5EU1NJKSkgKyBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJ5ZWxsb3ciLCBoaWdoID0gInJlZCIsIG5hLnZhbHVlID0gTkEpICsgCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gQWJzb2x1dGVfTGF0aXR1ZGUsIHkgPSBNYXhPZmZzZXQsICksIG1ldGhvZD1sbSApIAoKZ2dzYXZlKCJORFNTSW9mZnNldC5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCgpnZ3Bsb3QoRGVsdGFEYXRhd0xvY2F0aW9ucywgYWVzKHggPSBBYnNvbHV0ZV9MYXRpdHVkZSwgeSA9IE1heE9mZnNldCwgY29sb3IgPSByYW5nZU5EVkkpKSArIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gInllbGxvdyIsIGhpZ2ggPSAicmVkIiwgbmEudmFsdWUgPSBOQSkgKyAKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKHggPSBBYnNvbHV0ZV9MYXRpdHVkZSwgeSA9IE1heE9mZnNldCwgKSwgbWV0aG9kPWxtICkgCgpnZ3NhdmUoIk5EVklvZmZzZXQucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQoKYGBgCgoKTm93IGZvciB0aGUgbWFwczoKCmBgYHtyfQp3b3JsZCA8LSBnZ3Bsb3QoKSArCiAgYm9yZGVycygid29ybGQiLCBjb2xvdXIgPSAiZ3JheTg1IiwgZmlsbCA9ICJncmF5ODAiKSArCiAgdGhlbWVfbWFwKCkgCgpEZWx0YU9mZnNldE1hcCA8LSB3b3JsZCArCiAgZ2VvbV9wb2ludChhZXMoeCA9IExvbiwgeSA9IExhdCwgY29sb3IgPSBNYXhPZmZzZXQpLAogICAgICAgICAgICAgZGF0YSA9IERlbHRhRGF0YXdMb2NhdGlvbnMsIAogICAgICAgICAgICAgc2l6ZSA9IDUpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQoIGhpZ2ggPSAicmVkIiwgbG93ICA9ICJ5ZWxsb3ciKSArCiAgZ2d0aXRsZSgiT2Zmc2V0IEJldHdlZW4gTkRWSSBwZWFrIG9uIExhbmQgYW5kIE5EU1NJIHBlYWsgaW4gd2F0ZXIiKQoKRGVsdGFPZmZzZXRNYXAKZ2dzYXZlKCJEZWx0YU9mZnNldE1hcC5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCgpgYGAKCgpgYGB7cn0Kd29ybGQgPC0gZ2dwbG90KCkgKwogIGJvcmRlcnMoIndvcmxkIiwgY29sb3VyID0gImdyYXk4NSIsIGZpbGwgPSAiZ3JheTgwIikgKwogIHRoZW1lX21hcCgpIAoKRGVsdGFORFZJcmFuZ2VNYXAgPC0gd29ybGQgKwogIGdlb21fcG9pbnQoYWVzKHggPSBMb24sIHkgPSBMYXQsIGNvbG9yID0gcmFuZ2VORFZJKSwKICAgICAgICAgICAgIGRhdGEgPSBEZWx0YURhdGF3TG9jYXRpb25zLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQoIGhpZ2ggPSAicmVkIiwgbG93ICA9ICJ5ZWxsb3ciKSArIAogIGdndGl0bGUoIk5EVkkgcmFuZ2UiKQoKCkRlbHRhTkRTU0lyYW5nZU1hcCAgPC0gd29ybGQgKwogIGdlb21fcG9pbnQoYWVzKHggPSBMb24sIHkgPSBMYXQsIGNvbG9yID0gcmFuZ2VORFNTSSksCiAgICAgICAgICAgICBkYXRhID0gRGVsdGFEYXRhd0xvY2F0aW9ucywgCiAgICAgICAgICAgICBzaXplID0gNSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudCggaGlnaCA9ICJyZWQiLCBsb3cgPSAieWVsbG93IikgKyBnZ3RpdGxlKCJORFNTSSByYW5nZSIpIAoKRGVsdGFORFZJcmFuZ2VNYXAgCmdnc2F2ZSgiRGVsdGFORFZJcmFuZ2VNYXAucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpEZWx0YU5EU1NJcmFuZ2VNYXAKZ2dzYXZlKCJEZWx0YU5EU1NJcmFuZ2VNYXAucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQoKYGBgCgpMZXQncyBsb29rIGF0IHNvbWUgb2YgdGhlIGRhdGEuIApUbyBxdWFudGlmeSB0aGUgd2F0ZXIsIHdlIHVzZSBORFNTSS4gdG8gcXVhbnRpZnkgbGFuZCwgd2UgdXNlIE5EVkkuaGVyZSBpcyB0aGUgdGltZSBzZXJpZXMgZm9yIHRoZSBQYXJhbmEuIAoKYGBge3J9CkRlbHRhUGxvdHRlciA8LSBmdW5jdGlvbihEZWx0YU5hbWUpIHsKICAjQ291bnRzIGVhY2ggbW9udGgKICBudW1WZWcgPC0gRGVsdGFzQ2xlYW5lciAlPiUKICAgIHNlbGVjdChEZWx0YSwgc3VyZmFjZSwgbW9udGgsIG5kdmkpICU+JQogICAgZmlsdGVyKERlbHRhID09IERlbHRhTmFtZSAmIHN1cmZhY2UgPT0gIkxhbmQiICYgIWlzLm5hKG5kdmkpKSAlPiUKICAgIGdyb3VwX2J5KG1vbnRoKSAlPiUKICAgIHN1bW1hcml6ZShuID0gbigpKQogIAogIG51bVNlZCA8LSBEZWx0YXNDbGVhbmVyICU+JQogICAgc2VsZWN0KERlbHRhLCBzdXJmYWNlLCBtb250aCwgbmRzc2kpICU+JQogICAgZmlsdGVyKERlbHRhID09IERlbHRhTmFtZSAmCiAgICAgICAgICAgICBzdXJmYWNlID09ICJXYXRlciIgJiAhaXMubmEobmRzc2kpKSAlPiUKICAgIGdyb3VwX2J5KG1vbnRoKSAlPiUKICAgIHN1bW1hcml6ZShuID0gbigpKQogIAogICNIaWdobGlnaHQgdGhlIE1heGltdW0gYW5kIE1pbmltdW0gTW9udGggZm9yIGVhY2ggZGVsdGEsIE5EVkkgYW5kIE5EU1NJCiAgCiAgI0xBTkQKICBWZWcgPC0KICAgIGdncGxvdChkYXRhID0gZmlsdGVyKERlbHRhc0NsZWFuZXIsIERlbHRhID09IERlbHRhTmFtZSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1cmZhY2UgPT0gIkxhbmQiKSkgKwogICAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBuZHZpLCBncm91cCA9IG1vbnRoKSkgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6MTIpLCBicmVha3MgPSBjKDE6MTIpKSArCiAgICBleHBhbmRfbGltaXRzKHggPSBjKDEsIDEyKSwgeSA9IGMoMCwgMSkpICsKICAgIGdndGl0bGUoRGVsdGFOYW1lKSArCiAgICBnZW9tX3RleHQoZGF0YSA9IG51bVZlZywgYWVzKHkgPSAxLjA1LCB4ID0gbW9udGgsIGxhYmVsID0gbikpICsKICAgIGdlb21fYm94cGxvdCgKICAgICAgZGF0YSA9IGZpbHRlcigKICAgICAgICBEZWx0YXNDbGVhbmVyLAogICAgICAgIERlbHRhID09IERlbHRhTmFtZSAmCiAgICAgICAgICBzdXJmYWNlID09ICJMYW5kIiAmIG1vbnRoID09IERlbHRhTWF4TWluJE1heE1lYW5ORFZJbW9udGhbRGVsdGFNYXhNaW4kRGVsdGEgPT0gRGVsdGFOYW1lXSAKICAgICAgKSwKICAgICAgYWVzKHggPSBtb250aCwgeSA9IG5kdmksIGdyb3VwID0gbW9udGgpLAogICAgICBmaWxsID0gImdyZWVuIgogICAgKSArCiAgICBnZW9tX2JveHBsb3QoCiAgICAgIGRhdGEgPSBmaWx0ZXIoCiAgICAgICAgRGVsdGFzQ2xlYW5lciwKICAgICAgICBEZWx0YSA9PSBEZWx0YU5hbWUgJiAKICAgICAgICAgIHN1cmZhY2UgPT0gIkxhbmQiICYgbW9udGggPT0gRGVsdGFNYXhNaW4kTWluTWVhbk5EVkltb250aFtEZWx0YU1heE1pbiREZWx0YSA9PURlbHRhTmFtZV0KICAgICAgKSwKICAgICAgYWVzKHggPSBtb250aCwgeSA9IG5kdmksIGdyb3VwID0gbW9udGgpLAogICAgICBmaWxsID0gImJsdWUiCiAgICApCiAgCiAgCiAgU2VkIDwtCiAgICBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihEZWx0YXNDbGVhbmVyLCBEZWx0YSA9PSBEZWx0YU5hbWUgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBzdXJmYWNlID09ICJXYXRlciIpKSArCiAgICBnZW9tX2JveHBsb3QoYWVzKHggPSBtb250aCwgeSA9IG5kc3NpLCBncm91cCA9IG1vbnRoKSkgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6MTIpLCBicmVha3MgPSBjKDE6MTIpKSArCiAgICBleHBhbmRfbGltaXRzKHggPSBjKDEsIDEyKSwgeSA9IGMoMCwgMSkpICsKICAgIGdlb21fdGV4dChkYXRhID0gbnVtU2VkLCBhZXMoeSA9IDEuMDUsIHggPSBtb250aCwgbGFiZWwgPSBuKSkgKwogICAgZ2VvbV9ib3hwbG90KAogICAgICBkYXRhID0gZmlsdGVyKAogICAgICAgIERlbHRhc0NsZWFuZXIsCiAgICAgICAgRGVsdGEgPT0gRGVsdGFOYW1lICYKICAgICAgICAgIHN1cmZhY2UgPT0gIldhdGVyIiAmIG1vbnRoID09IERlbHRhTWF4TWluJE1heE1lYW5ORFNTSW1vbnRoW0RlbHRhTWF4TWluJERlbHRhID09IERlbHRhTmFtZV0KICAgICAgKSwKICAgICAgYWVzKHggPSBtb250aCwgeSA9IG5kc3NpLCBncm91cCA9IG1vbnRoKSwKICAgICAgZmlsbCA9ICJncmVlbiIKICAgICkgKwogICAgZ2VvbV9ib3hwbG90KAogICAgICBkYXRhID0gZmlsdGVyKAogICAgICAgIERlbHRhc0NsZWFuZXIsCiAgICAgICAgRGVsdGEgPT0gRGVsdGFOYW1lICYKICAgICAgICAgIHN1cmZhY2UgPT0gIldhdGVyIiAmIG1vbnRoID09IERlbHRhTWF4TWluJE1pbk1lYW5ORFNTSW1vbnRoW0RlbHRhTWF4TWluJERlbHRhID09IERlbHRhTmFtZV0KICAgICAgKSwKICAgICAgYWVzKHggPSBtb250aCwgeSA9IG5kc3NpLCBncm91cCA9IG1vbnRoKSwKICAgICAgZmlsbCA9ICJibHVlIgogICAgKQogIAogIHJldHVybihncmlkLmFycmFuZ2UoVmVnLCBTZWQsIG5yb3cgPSAyKSkKfQpgYGAKCgpIZXJlIGlzIGFuICdPZmZzZXQnIGV4YW1wbGUgZnJvbSB0aGUgUGFyYW5hOgpgYGB7cn0KRGVsdGFQbG90dGVyKCJQYXJhbmEiKQpgYGAKCgphbmQgbm93IGFuIGluLXBoYXNlIGV4YW1wbGUgZnJvbQpgYGB7cn0KRGVsdGFQbG90dGVyKCJNYWdkYWxlbmEiKQpgYGAKCgphbmQgdGhlIEVicm86CmBgYHtyfQpEZWx0YVBsb3R0ZXIoIktyaXNobmEiKQpgYGAKCgphbmQgdGhlIFRhbmEKYGBge3J9CkRlbHRhUGxvdHRlcigiVGFuYSIpCmBgYAoKYW5kIHRoZSBUYW5hCmBgYHtyfQpEZWx0YVBsb3R0ZXIoIkdvZGF2YXJpIikKRGVsdGFQbG90dGVyKCJLcmlzaG5hIikKYGBgCgoKCgoKTm93IGZvciBzb21lIHdvcmsgd2l0aCBHUkRDIGRhdGE6CmBgYHtyfQojaW1wb3J0IHRoZSBkYXRhIChtb250aGx5IG1lYW5zIGZvciAyMSBzdGF0aW9ucykKRGVsdGFzR1JEQyAgPC0gcmVhZF9jc3YoIi4uL2RhdGEvR1JEQ3N0YXRpb25zLmNzdiIpCgojY2FsY3VsYXRlIHRoZSBtZWFuIG9mIHRoZSBtb250aGx5IG1lYW5zCkRlbHRhc0dSREN3TWVhbiA8LSBEZWx0YXNHUkRDICU+JSAKICAgIHJvd3dpc2UoKSAlPiUgCiAgICBtdXRhdGUoTU1EPW1lYW4oYyhKYW51YXJ5LEZlYnJ1YXJ5LE1hcmNoLEFwcmlsLAogICAgICAgICAgICAgICAgICAgIE1heSxKdW5lLEp1bHksQXVndXN0LAogICAgICAgICAgICAgICAgICAgIFNlcHRlbWJlcixPY3RvYmVyLE5vdmVtYmVyLERlY2VtYmVyKSkpCgpEZWx0YXNHUkRDd01lYW4gPC0gRGVsdGFzR1JEQ3dNZWFuICU+JSAKICByb3d3aXNlKCkgJT4lIAogIG11dGF0ZShSYW5nZV9EaXNjaGFyZ2UgPSBtYXgoYyhKYW51YXJ5LEZlYnJ1YXJ5LE1hcmNoLEFwcmlsLAogICAgICAgICAgICAgIE1heSxKdW5lLEp1bHksQXVndXN0LAogICAgICAgICAgICAgIFNlcHRlbWJlcixPY3RvYmVyLE5vdmVtYmVyLERlY2VtYmVyKSkgLSAKICAgICAgICAgICBtaW4oYyhKYW51YXJ5LEZlYnJ1YXJ5LE1hcmNoLEFwcmlsLAogICAgICAgICAgICAgIE1heSxKdW5lLEp1bHksQXVndXN0LAogICAgICAgICAgICAgIFNlcHRlbWJlcixPY3RvYmVyLE5vdmVtYmVyLERlY2VtYmVyKSkKICAgICAgICAgICApCiAgICAgICAgCgojam9pbiB0byBsb2NhdGlvbiBkYXRhOgpEZWx0YXdMb2NHUkRDIDwtIGxlZnRfam9pbihEZWx0YURhdGF3TG9jYXRpb25zLCBEZWx0YXNHUkRDd01lYW4sIGJ5ID0gYygiRGVsdGEiID0gIkRlbHRhcyIpKQoKCiNwbG90IG1lYW4gb2YgbW9udGhseSBtZWFucyBhZ2FpbnN0IE5EU1NJCmdncGxvdChEZWx0YXdMb2NHUkRDLCBhZXMoeSA9IFJhbmdlX0Rpc2NoYXJnZSwgeCA9IHJhbmdlTkRTU0kpKSArIGdlb21fcG9pbnQoKSArIHNjYWxlX3lfY29udGludW91cyh0cmFucz0nbG9nMTAnKQoKZ2dzYXZlKCJHUkRDTkRTU0kucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQoKZ2dwbG90KERlbHRhd0xvY0dSREMsIGFlcyh5ID0gUmFuZ2VfRGlzY2hhcmdlLCB4ID0gTWF4TWVhbk5EU1NJKSkgKyBnZW9tX3BvaW50KCkgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykKYGBgCgoKCmBgYHtyfQoKCiNyZW5hbWUgdGhlIG1vbnRocyBieSBudW1iZXJzIGFuZCB0aWR5IHRoZSBHUkRDIGRhdGEKRGVsdGFzRGlzY2hhcmdlIDwtIERlbHRhc0dSREMgJT4lCiAgcmVuYW1lKERlbHRhID0gRGVsdGFzLCIxIiA9IEphbnVhcnksICIyIj0gRmVicnVhcnksICIzIj0gTWFyY2gsICI0Ij0gQXByaWwsCiAgICAgICAgICI1Ij1NYXksICI2Ij1KdW5lLCAiNyI9SnVseSwgIjgiPSBBdWd1c3QsICI5IiA9IFNlcHRlbWJlciwgIjEwIj1PY3RvYmVyLCAKICAgICAgICAgIjExIj1Ob3ZlbWJlciwgIjEyIj1EZWNlbWJlcikgJT4lCiAgc2VsZWN0KERlbHRhLCAiMSIgLCAiMiIgLCAiMyIsICI0IiwiNSIsICI2IiwgIjciLCAiOCIsICI5IiwgIjEwIiwgIjExIiwgIjEyIikgJT4lCiAgcGl2b3RfbG9uZ2VyKC1EZWx0YSwgbmFtZXNfdG8gPSAibW9udGgiLCB2YWx1ZXNfdG8gPSAiZGlzY2hhcmdlIikKCiNmaW5kIG1heCBHUkRDIG1vbnRoIGZvciBlYWNoIGRlbHRhCkRlbHRhTWF4RGlzY2hhcmdlIDwtIAogIERlbHRhc0Rpc2NoYXJnZSAlPiUgCiAgZ3JvdXBfYnkoRGVsdGEpICU+JSAKICBzbGljZSh3aGljaC5tYXgoZGlzY2hhcmdlKSkgJT4lIAogIHJlbmFtZShNYXhEaXNjaGFyZ2VNb250aCA9IG1vbnRoLCBNYXhEaXNjaGFyZ2UgPSBkaXNjaGFyZ2UpIAoKCkRlbHRhTWF4RGlzY2hhcmdlJE1heERpc2NoYXJnZU1vbnRoID0gYXMubnVtZXJpYyhEZWx0YU1heERpc2NoYXJnZSRNYXhEaXNjaGFyZ2VNb250aCkKCgojam9pbiB3aXRoIG90aGVyIGRlbHRhIGRhdGEKRGVsdGFNYXhNaW5EaXNjaGFyZ2UgPC0gbGVmdF9qb2luKERlbHRhTWF4TWluLCBEZWx0YU1heERpc2NoYXJnZSwgYnkgPSAnRGVsdGEnKQoKI2NhbGN1bGF0ZSBvZmZzZXQKRGVsdGFNYXhNaW5EaXNjaGFyZ2UgPC0gRGVsdGFNYXhNaW5EaXNjaGFyZ2UgJT4lCiAgbXV0YXRlKCBEaXNzT2ZmID0gaWZfZWxzZShhYnMoTWF4RGlzY2hhcmdlTW9udGggLSBNYXhNZWFuTkRTU0ltb250aCkgPiA2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgMTIgLSBhYnMoTWF4RGlzY2hhcmdlTW9udGggLSBNYXhNZWFuTkRTU0ltb250aCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMoTWF4RGlzY2hhcmdlTW9udGggLSBNYXhNZWFuTkRTU0ltb250aCkpCiAgICAgICAgICApCgojQ29tcGFyZSBvZmZzZXQgd2l0aCBORFNTSSAoZGVsdGFtYXhtaW4kbWF4bWVhbk5EU1NJbW9udGgpCmdncGxvdChEZWx0YU1heE1pbkRpc2NoYXJnZSwgYWVzKHkgPSBEZWx0YSwgeCA9IERpc3NPZmYpKSArIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygxOjYpLCBicmVha3MgPSBjKDE6NikpICsKICBleHBhbmRfbGltaXRzKHggPSBjKDAsNikpICArIAogIGdndGl0bGUoIkRpc09mZnNldCIpCgoKI2p1c3QgdG8gY2hlY2sKCmNoZWNrIDwtIERlbHRhTWF4TWluRGlzY2hhcmdlICU+JQogIHNlbGVjdChEZWx0YSxNYXhNZWFuTkRWSW1vbnRoLCBNYXhNZWFuTkRTU0ltb250aCwgTWF4RGlzY2hhcmdlTW9udGgsIERpc3NPZmYpCgoKI2pvaW4gbGF0IGRhdGEKRGVsdGFEYXRhd0xvY2F0aW9ucyA8LSBsZWZ0X2pvaW4oRGVsdGFNYXhNaW5EaXNjaGFyZ2UsIERlbHRhTG9jYXRpb25zLCBieSA9IGMoIkRlbHRhIiA9ICJEZWx0YXMiKSkKCkRlbHRhRGF0YXdMb2NhdGlvbnMgPC0gRGVsdGFEYXRhd0xvY2F0aW9ucyAlPiUKICBtdXRhdGUoQWJzb2x1dGVfTGF0aXR1ZGU9IGFicyhMYXQpKQoKIyBwbG90IG9mZnNldCBvbiBncmFwaCBieSBsYXQKZ2dwbG90KERlbHRhRGF0YXdMb2NhdGlvbnMsIGFlcyh4ID0gQWJzb2x1dGVfTGF0aXR1ZGUsIHkgPSBEaXNzT2ZmKSkgKyBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJ5ZWxsb3ciLCBoaWdoID0gInJlZCIsIG5hLnZhbHVlID0gTkEpIAogICMrIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IEFic29sdXRlX0xhdGl0dWRlLCB5ID0gRGlzc09mZiwgKSwgbWV0aG9kPWxtICkgCgpnZ3NhdmUoIkRpc09mZnNldC5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCgojcGxvdCBvZmZzZXQgb24gbWFwCkRlbHRhRGlzT2Zmc2V0TWFwIDwtIHdvcmxkICsKICBnZW9tX3BvaW50KGFlcyh4ID0gTG9uLCB5ID0gTGF0LCBjb2xvciA9IERpc3NPZmYpLAogICAgICAgICAgICAgZGF0YSA9IERlbHRhRGF0YXdMb2NhdGlvbnMsIAogICAgICAgICAgICAgc2l6ZSA9IDUpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQoIGhpZ2ggPSAicmVkIiwgbG93ICA9ICJ5ZWxsb3ciKSArCiAgZ2d0aXRsZSgiT2Zmc2V0IEJldHdlZW4gR1JEQyBkaXNjaGFyZ2UgcGVhayBhbmQgTkRTU0kgcGVhayBpbiB3YXRlciIpCgpEZWx0YURpc09mZnNldE1hcAojZ2dzYXZlKCJEZWx0YU9mZnNldE1hcC5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCmBgYAoKCgoK